#include "image.h"
#include <iostream>

Image::Image(const char* imgPath)
{
	img = cvLoadImage(imgPath);
	if (img == NULL)
	{
		img = cvLoadImage("../img/deuxcarre.pgm");
		this->imgPath = "../img/deuxcarre.pgm";
	}
	else
		this->imgPath = imgPath;
	
	Node* root = new Node(0, 0, img->width - 1, img->height - 1, 0, NULL);
	quad = new Quadtree(root);
	
	colorResult = true;
	aleaColorResult = false;
	reverseMerge = false;
	splitMinPixel = 1;
	splitThreshold = 10;
	mergeThreshold = 10;
	homogeneousFct = 1;
}

Image::~Image()
{
	cvReleaseImage(&img);
	cvReleaseImage(&splitImg);
	cvReleaseImage(&mergeImg);
	delete quad;
}

IplImage* Image::Split()
{
	quad->ReInit();
	
	// On recupere le vecteur de noeuds du quadtree
	const std::vector<Node*>& allNode = quad->GetAllNode();
	
	bool run = true;
	while (run)
	{
		run = false;
		int maxLevel = allNode.back()->GetNodeLevel();
		
		size_t position =  allNode.size();
		std::vector<Node*>::const_reverse_iterator rIt = allNode.rbegin();
		while (rIt != allNode.rend() && (*rIt)->GetNodeLevel() == maxLevel)
		{
			++rIt;
			position--;
		}
		
		size_t endMaxLevel = allNode.size();
		int i = 1;
		for (size_t j = position; j < endMaxLevel; j++)
		{
			bool isHomogeneous;
			if (homogeneousFct == 1)
				isHomogeneous = allNode.at(j)->IsHomogeneous(img, splitThreshold, splitMinPixel);
			else
				isHomogeneous = allNode.at(j)->IsHomogeneousDeviation(img, splitThreshold, splitMinPixel);
			
			if (!isHomogeneous)
			{
				quad->AddNode(allNode.at(j));
				run = true;
			}
			i++;
		}
	}
	
	splitImg = cvCloneImage(img);
	quad->Display(splitImg);
	return splitImg;
}

IplImage* Image::Merge()
{
	mergeImg = cvCreateImage(cvSize(img->width, img->height), IPL_DEPTH_8U, 3);
	
	// On recupere le vecteur de noeud du quadtree
	const std::vector<Node*>& allNode = quad->GetAllNode();
	
	std::vector<Node*>::const_iterator it;
	for (it = allNode.begin(); it != allNode.end(); ++it)
	{
		if ((*it)->GetColored() == false)
		{
			// Si le noeud n'est pas encore colorie
			
			CvScalar pixel;
			if (aleaColorResult)
			{
				for ( int i = 0 ; i < 3 ; i++)
					pixel.val[i] = rand()%255;
			}
			else
			{
				pixel.val[0] = (*it)->GetColorAverageBlue();
				pixel.val[1] = (*it)->GetColorAverageGreen();
				pixel.val[2] = (*it)->GetColorAverageRed();
			}
			
			int averageMaxBlue = (*it)->GetColorAverage() + mergeThreshold;
			int averageMinBlue = (*it)->GetColorAverage() - mergeThreshold;
			if (averageMaxBlue > 255)
				averageMaxBlue = 255;
			if (averageMinBlue < 0)
				averageMinBlue = 0;
			
			int averageMaxGreen = (*it)->GetColorAverageGreen() + mergeThreshold;
			int averageMinGreen = (*it)->GetColorAverageGreen() - mergeThreshold;
			if (averageMaxGreen > 255)
				averageMaxGreen = 255;
			if (averageMinGreen < 0)
				averageMinGreen = 0;
			
			int averageMaxRed = (*it)->GetColorAverageRed() + mergeThreshold;
			int averageMinRed = (*it)->GetColorAverageRed() - mergeThreshold;
			if (averageMaxRed > 255)
				averageMaxRed = 255;
			if (averageMinRed < 0)
				averageMinRed = 0;
			
			int averageMax = (averageMaxGreen + averageMaxRed + averageMaxBlue) / 3;
			int averageMin = (averageMinGreen + averageMinRed + averageMinBlue) / 3;
		
			(*it)->ColorNode(mergeImg, pixel, averageMax, averageMin);
		}
	}
	
	if (colorResult)
		return mergeImg;
	else
	{
		IplImage* mergeImgNB = cvCreateImage(cvSize(img->width, img->height), IPL_DEPTH_8U, 1);
		cvCvtColor(mergeImg, mergeImgNB, CV_BGR2GRAY);
		return mergeImgNB;
	}
}

IplImage* Image::ReverseMerge()
{
	mergeImg = cvCreateImage(cvSize(img->width, img->height), IPL_DEPTH_8U, 3);
	
	// On recupere le vecteur de noeud du quadtree
	const std::vector<Node*>& allNode = quad->GetAllNode();
	
	std::vector<Node*>::const_reverse_iterator rIt;
	for (rIt = allNode.rbegin(); rIt != allNode.rend(); ++rIt)
	{
		if ((*rIt)->GetColored() == false)
		{
			// Si le noeud n'est pas encore colorie
			
			CvScalar pixel;
			if (aleaColorResult)
			{
				for ( int i = 0 ; i < 3 ; i++)
					pixel.val[i] = rand()%255;
			}
			else
			{
				pixel.val[0] = (*rIt)->GetColorAverageBlue();
				pixel.val[1] = (*rIt)->GetColorAverageGreen();
				pixel.val[2] = (*rIt)->GetColorAverageRed();
			}
			
			int averageMaxBlue = (*rIt)->GetColorAverage() + mergeThreshold;
			int averageMinBlue = (*rIt)->GetColorAverage() - mergeThreshold;
			if (averageMaxBlue > 255)
				averageMaxBlue = 255;
			if (averageMinBlue < 0)
				averageMinBlue = 0;
			
			int averageMaxGreen = (*rIt)->GetColorAverageGreen() + mergeThreshold;
			int averageMinGreen = (*rIt)->GetColorAverageGreen() - mergeThreshold;
			if (averageMaxGreen > 255)
				averageMaxGreen = 255;
			if (averageMinGreen < 0)
				averageMinGreen = 0;
			
			int averageMaxRed = (*rIt)->GetColorAverageRed() + mergeThreshold;
			int averageMinRed = (*rIt)->GetColorAverageRed() - mergeThreshold;
			if (averageMaxRed > 255)
				averageMaxRed = 255;
			if (averageMinRed < 0)
				averageMinRed = 0;
			
			int averageMax = (averageMaxGreen + averageMaxRed + averageMaxBlue) / 3;
			int averageMin = (averageMinGreen + averageMinRed + averageMinBlue) / 3;
		
			(*rIt)->ColorNode(mergeImg, pixel, averageMax, averageMin);
		}
	}
	
	if (colorResult)
		return mergeImg;
	else
	{
		IplImage* mergeImgNB = cvCreateImage(cvSize(img->width, img->height), IPL_DEPTH_8U, 1);
		cvCvtColor(mergeImg, mergeImgNB, CV_BGR2GRAY);
		return mergeImgNB;
	}
}

